#!/usr/bin/env python3
"""
金融风控自定义评估指标 - Auto-sklearn业务导向建模
=============================================

这是一个完整的金融风控建模示例，展示如何设计和实现
业务导向的自定义评估指标，将成本考虑融入AutoML优化过程。

功能特色：
- 业务价值导向的自定义指标
- 成本敏感的模型优化
- 风险调整收益计算
- 决策阈值优化
"""

import os
import sys
import warnings
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets, model_selection, metrics
from sklearn.metrics import confusion_matrix, classification_report
import autosklearn.classification
import autosklearn.metrics
from datetime import datetime
import joblib
from scipy import stats
import itertools

# 设置警告过滤和显示
warnings.filterwarnings('ignore')
plt.style.use('seaborn-v0_8')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

class BusinessMetrics:
    """业务导向的自定义评估指标类"""
    
    @staticmethod
    def business_value_score(y_true, y_pred, cost_fp=500, cost_fn=5000, profit_tp=200):
        """
        业务价值分数 - 核心业务指标
        
        Args:
            y_true: 真实标签
            y_pred: 预测标签 
            cost_fp: 假阳性成本 (误拒好客户)
            cost_fn: 假阴性成本 (误批坏客户)
            profit_tp: 真阳性收益 (正确批准)
        
        Returns:
            标准化的业务价值分数 [0,1]
        """
        tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()
        
        # 计算总业务价值
        total_value = (tp * profit_tp) - (fp * cost_fp) - (fn * cost_fn)
        
        # 最大可能价值 (所有正例都正确预测)
        positive_samples = np.sum(y_true == 1)
        max_possible_value = positive_samples * profit_tp
        
        # 标准化到 [0, 1] 区间
        if max_possible_value == 0:
            return 0.0
        
        normalized_value = total_value / max_possible_value
        
        # 确保不低于0 (最差情况)
        return max(0.0, normalized_value)
    
    @staticmethod
    def cost_sensitive_accuracy(y_true, y_pred, cost_ratio=10):
        """
        成本敏感准确率
        
        Args:
            y_true: 真实标签
            y_pred: 预测标签
            cost_ratio: 假阴性与假阳性的成本比率
        """
        cm = confusion_matrix(y_true, y_pred)
        tn, fp, fn, tp = cm.ravel()
        
        # 加权正确预测
        weighted_correct = tn + tp * cost_ratio
        weighted_total = (tn + fp) + (fn + tp) * cost_ratio
        
        return weighted_correct / weighted_total if weighted_total > 0 else 0
    
    @staticmethod
    def adjusted_fbeta_score(y_true, y_pred, beta=2.0, cost_weight=0.3):
        """
        调整后的F-beta分数，重点关注召回率以减少假阴性
        
        Args:
            beta: beta参数，>1时更重视召回率
            cost_weight: 成本惩罚权重
        """
        precision = metrics.precision_score(y_true, y_pred, zero_division=0)
        recall = metrics.recall_score(y_true, y_pred, zero_division=0)
        
        if precision + recall == 0:
            return 0
        
        fbeta = (1 + beta**2) * precision * recall / (beta**2 * precision + recall)
        
        # 成本调整 - 假阴性惩罚
        fn_rate = np.sum((y_true == 1) & (y_pred == 0)) / np.sum(y_true == 1) if np.sum(y_true == 1) > 0 else 0
        cost_penalty = cost_weight * fn_rate
        
        return fbeta * (1 - cost_penalty)
    
    @staticmethod
    def profit_curve_score(y_true, y_pred_proba, cost_fp=500, cost_fn=5000, profit_tp=200):
        """
        利润曲线下面积分数
        
        Args:
            y_pred_proba: 预测概率
        """
        # 按概率排序
        sorted_indices = np.argsort(y_pred_proba[:, 1])[::-1]
        y_true_sorted = y_true[sorted_indices]
        
        cumulative_profit = []
        cumulative_tp = 0
        cumulative_fp = 0
        
        for i, true_label in enumerate(y_true_sorted):
            if true_label == 1:
                cumulative_tp += 1
                profit = profit_tp
            else:
                cumulative_fp += 1
                profit = -cost_fp
            
            # 考虑未处理的假阴性成本
            remaining_positives = np.sum(y_true_sorted[i+1:] == 1)
            fn_cost = remaining_positives * cost_fn
            
            net_profit = (cumulative_tp * profit_tp) - (cumulative_fp * cost_fp) - fn_cost
            cumulative_profit.append(net_profit)
        
        # 计算曲线下面积 (归一化)
        max_profit = np.sum(y_true == 1) * profit_tp
        min_profit = -np.sum(y_true == 0) * cost_fp - np.sum(y_true == 1) * cost_fn
        
        if max_profit == min_profit:
            return 0
        
        auc_profit = np.trapz(cumulative_profit) / len(cumulative_profit)
        normalized_auc = (auc_profit - min_profit) / (max_profit - min_profit)
        
        return max(0, normalized_auc)

class FinancialRiskClassifier:
    """金融风控自定义指标分类器"""
    
    def __init__(self, time_limit=600, per_run_limit=120):
        """
        初始化分类器
        
        Args:
            time_limit: Auto-sklearn总运行时间（秒）
            per_run_limit: 单个模型最大运行时间（秒）
        """
        self.time_limit = time_limit
        self.per_run_limit = per_run_limit
        self.automl = None
        self.business_metrics = BusinessMetrics()
        self.results = {}
        
        # 业务成本参数
        self.cost_matrix = {
            'fp_cost': 500,    # 误拒好客户成本
            'fn_cost': 5000,   # 误批坏客户成本  
            'tp_profit': 200   # 正确批准收益
        }
        
    def load_and_prepare_data(self):
        """加载和预处理德国信贷数据集"""
        print("正在加载德国信贷数据集...")
        
        # 加载德国信贷数据
        X, y = datasets.fetch_openml(
            data_id=31, 
            return_X_y=True, 
            as_frame=True,
            parser='auto'
        )
        
        print(f"数据加载成功！")
        print(f"特征矩阵形状: {X.shape}")
        print(f"目标变量形状: {y.shape}")
        
        # 处理目标变量 (bad -> 1, good -> 0)
        y_processed = np.array([1 if val == "bad" else 0 for val in y])
        
        # 数据集基本信息
        n_samples, n_features = X.shape
        positive_rate = np.mean(y_processed)
        
        print(f"\n📊 数据集概览:")
        print(f"- 样本数量: {n_samples:,}")
        print(f"- 特征数量: {n_features}")
        print(f"- 坏客户比例: {positive_rate:.1%}")
        print(f"- 好客户比例: {(1-positive_rate):.1%}")
        print(f"- 类别不平衡比: {(1-positive_rate)/positive_rate:.1f}:1")
        
        # 训练集和测试集分割
        X_train, X_test, y_train, y_test = model_selection.train_test_split(
            X, y_processed, 
            test_size=0.25, 
            random_state=42, 
            stratify=y_processed
        )
        
        print(f"\n📝 数据分割:")
        print(f"- 训练集: {X_train.shape[0]} 样本")
        print(f"- 测试集: {X_test.shape[0]} 样本")
        print(f"- 训练集坏客户比例: {np.mean(y_train):.1%}")
        print(f"- 测试集坏客户比例: {np.mean(y_test):.1%}")
        
        return X_train, X_test, y_train, y_test
    
    def analyze_cost_structure(self, y_train, y_test):
        """分析成本结构和业务影响"""
        print("\n💰 成本结构分析")
        print("=" * 50)
        
        n_train_positive = np.sum(y_train)
        n_train_negative = len(y_train) - n_train_positive
        n_test_positive = np.sum(y_test) 
        n_test_negative = len(y_test) - n_test_positive
        
        print("成本矩阵定义:")
        print(f"- 误批坏客户成本: ¥{self.cost_matrix['fn_cost']:,}")
        print(f"- 误拒好客户成本: ¥{self.cost_matrix['fp_cost']:,}")
        print(f"- 正确批准收益: ¥{self.cost_matrix['tp_profit']:,}")
        
        print(f"\n潜在业务影响 (测试集):")
        max_loss_fn = n_test_positive * self.cost_matrix['fn_cost']
        max_loss_fp = n_test_negative * self.cost_matrix['fp_cost']
        max_profit = n_test_positive * self.cost_matrix['tp_profit']
        
        print(f"- 最大假阴性损失: ¥{max_loss_fn:,}")
        print(f"- 最大假阳性损失: ¥{max_loss_fp:,}")
        print(f"- 最大可能收益: ¥{max_profit:,}")
        
        # 不同策略的理论表现
        print(f"\n策略对比分析:")
        print(f"- 全部拒绝: 损失 ¥0，收益 ¥0")
        print(f"- 全部批准: 损失 ¥{max_loss_fn:,}，收益 ¥{max_profit:,}，净值 ¥{max_profit-max_loss_fn:,}")
        print(f"- 随机决策: 期望损失约 ¥{(max_loss_fn + max_loss_fp)/2:,.0f}")
        
    def create_custom_metrics(self):
        """创建自定义评估指标"""
        print("\n正在创建自定义评估指标...")
        
        # 1. 业务价值分数
        business_value_scorer = autosklearn.metrics.make_scorer(
            name="business_value",
            score_func=self.business_metrics.business_value_score,
            optimum=1.0,
            greater_is_better=True,
            needs_proba=False,
            needs_threshold=False,
            cost_fp=self.cost_matrix['fp_cost'],
            cost_fn=self.cost_matrix['fn_cost'], 
            profit_tp=self.cost_matrix['tp_profit']
        )
        
        # 2. 成本敏感准确率
        cost_accuracy_scorer = autosklearn.metrics.make_scorer(
            name="cost_sensitive_accuracy",
            score_func=self.business_metrics.cost_sensitive_accuracy,
            optimum=1.0,
            greater_is_better=True,
            needs_proba=False,
            needs_threshold=False,
            cost_ratio=self.cost_matrix['fn_cost'] / self.cost_matrix['fp_cost']
        )
        
        # 3. 调整后F-beta分数
        adjusted_fbeta_scorer = autosklearn.metrics.make_scorer(
            name="adjusted_fbeta",
            score_func=self.business_metrics.adjusted_fbeta_score,
            optimum=1.0,
            greater_is_better=True,
            needs_proba=False,
            needs_threshold=False,
            beta=2.0,
            cost_weight=0.3
        )
        
        self.custom_scorers = {
            'business_value': business_value_scorer,
            'cost_accuracy': cost_accuracy_scorer,
            'adjusted_fbeta': adjusted_fbeta_scorer
        }
        
        print("✅ 自定义指标创建完成")
        return business_value_scorer
    
    def create_automl_classifier(self, primary_metric):
        """创建Auto-sklearn分类器"""
        print(f"\n正在创建Auto-sklearn分类器 (优化指标: {primary_metric.name})...")
        
        self.automl = autosklearn.classification.AutoSklearnClassifier(
            time_left_for_this_task=self.time_limit,
            per_run_time_limit=self.per_run_limit,
            initial_configurations_via_metalearning=15,
            smac_scenario_args={'runcount_limit': 30},
            resampling_strategy='cv',
            resampling_strategy_arguments={'folds': 5},
            tmp_folder="/tmp/autosklearn_financial_risk",
            seed=42,
            memory_limit=4096,
            metric=primary_metric,
            # 算法选择：偏向处理不平衡数据的算法
            include={
                'classifier': [
                    'random_forest', 'extra_trees', 'gradient_boosting',
                    'k_nearest_neighbors', 'libsvm_svc'
                ],
                'feature_preprocessor': [
                    'select_percentile_classification', 'select_rates',
                    'polynomial', 'kernel_pca'
                ]
            }
        )
        
        return self.automl
    
    def train_model(self, X_train, y_train):
        """训练Auto-sklearn模型"""
        print(f"\n开始训练业务导向模型 (时间限制: {self.time_limit}秒)...")
        print("=" * 60)
        
        start_time = datetime.now()
        
        # 训练模型
        self.automl.fit(
            X_train, y_train,
            dataset_name="german_credit_custom_metrics"
        )
        
        end_time = datetime.now()
        training_time = (end_time - start_time).total_seconds()
        
        print(f"\n✅ 模型训练完成，耗时: {training_time:.1f}秒")
        print("=" * 60)
        
        return training_time
    
    def calculate_all_metrics(self, y_true, y_pred, y_pred_proba=None):
        """计算所有评估指标"""
        metrics_dict = {}
        
        # 基础指标
        metrics_dict['accuracy'] = metrics.accuracy_score(y_true, y_pred)
        metrics_dict['precision'] = metrics.precision_score(y_true, y_pred, zero_division=0)
        metrics_dict['recall'] = metrics.recall_score(y_true, y_pred, zero_division=0)
        metrics_dict['f1'] = metrics.f1_score(y_true, y_pred, zero_division=0)
        
        if y_pred_proba is not None:
            metrics_dict['auc'] = metrics.roc_auc_score(y_true, y_pred_proba[:, 1])
        
        # 自定义业务指标
        metrics_dict['business_value'] = self.business_metrics.business_value_score(
            y_true, y_pred, 
            cost_fp=self.cost_matrix['fp_cost'],
            cost_fn=self.cost_matrix['fn_cost'],
            profit_tp=self.cost_matrix['tp_profit']
        )
        
        metrics_dict['cost_sensitive_accuracy'] = self.business_metrics.cost_sensitive_accuracy(
            y_true, y_pred, 
            cost_ratio=self.cost_matrix['fn_cost'] / self.cost_matrix['fp_cost']
        )
        
        metrics_dict['adjusted_fbeta'] = self.business_metrics.adjusted_fbeta_score(
            y_true, y_pred, beta=2.0, cost_weight=0.3
        )
        
        # 成本分析
        tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()
        total_cost = fp * self.cost_matrix['fp_cost'] + fn * self.cost_matrix['fn_cost']
        total_profit = tp * self.cost_matrix['tp_profit']
        net_value = total_profit - total_cost
        
        metrics_dict['total_cost'] = total_cost
        metrics_dict['total_profit'] = total_profit
        metrics_dict['net_business_value'] = net_value
        
        return metrics_dict
    
    def evaluate_model(self, X_train, X_test, y_train, y_test):
        """全面评估模型性能"""
        print("\n正在评估模型性能...")
        
        # 生成预测
        train_pred = self.automl.predict(X_train)
        test_pred = self.automl.predict(X_test)
        
        # 生成概率预测
        try:
            train_pred_proba = self.automl.predict_proba(X_train)
            test_pred_proba = self.automl.predict_proba(X_test)
        except:
            print("⚠️  无法获取概率预测")
            train_pred_proba = None
            test_pred_proba = None
        
        # 计算所有指标
        train_metrics = self.calculate_all_metrics(y_train, train_pred, train_pred_proba)
        test_metrics = self.calculate_all_metrics(y_test, test_pred, test_pred_proba)
        
        # 保存结果
        self.results = {
            'train_predictions': train_pred,
            'test_predictions': test_pred,
            'train_pred_proba': train_pred_proba,
            'test_pred_proba': test_pred_proba,
            'train_metrics': train_metrics,
            'test_metrics': test_metrics,
            'y_train': y_train,
            'y_test': y_test,
            'confusion_matrix': confusion_matrix(y_test, test_pred)
        }
        
        # 显示评估结果
        self._display_evaluation_results(train_metrics, test_metrics)
        
        return train_metrics, test_metrics
    
    def _display_evaluation_results(self, train_metrics, test_metrics):
        """显示评估结果"""
        print("\n📊 模型性能综合评估")
        print("=" * 80)
        print(f"{'指标':<25} {'训练集':<15} {'测试集':<15} {'业务含义':<25}")
        print("-" * 80)
        
        metrics_info = [
            ('accuracy', '准确率', '整体预测准确性'),
            ('precision', '精度', '批准客户中好客户比例'),
            ('recall', '召回率', '好客户被正确识别比例'),
            ('f1', 'F1分数', '精度和召回率的调和平均'),
            ('business_value', '业务价值分数', '标准化业务价值'),
            ('cost_sensitive_accuracy', '成本敏感准确率', '加权准确率'),
            ('adjusted_fbeta', '调整F-beta', '成本调整的F分数')
        ]
        
        if 'auc' in test_metrics:
            metrics_info.append(('auc', 'AUC', '排序性能'))
        
        for metric_key, metric_name, description in metrics_info:
            train_val = train_metrics.get(metric_key, 0)
            test_val = test_metrics.get(metric_key, 0)
            print(f"{metric_name:<25} {train_val:<15.4f} {test_val:<15.4f} {description:<25}")
        
        # 业务价值分析
        print(f"\n💰 业务价值分析 (测试集):")
        print(f"- 总成本: ¥{test_metrics['total_cost']:,}")
        print(f"- 总收益: ¥{test_metrics['total_profit']:,}")
        print(f"- 净业务价值: ¥{test_metrics['net_business_value']:,}")
        
        # 混淆矩阵分析
        cm = self.results['confusion_matrix']
        tn, fp, fn, tp = cm.ravel()
        print(f"\n📋 决策结果分析:")
        print(f"- 正确拒绝(TN): {tn} 客户")
        print(f"- 误拒好客户(FP): {fp} 客户 (损失 ¥{fp * self.cost_matrix['fp_cost']:,})")
        print(f"- 误批坏客户(FN): {fn} 客户 (损失 ¥{fn * self.cost_matrix['fn_cost']:,})")
        print(f"- 正确批准(TP): {tp} 客户 (收益 ¥{tp * self.cost_matrix['tp_profit']:,})")
        
        # 性能诊断
        self._diagnose_business_performance(test_metrics, cm)
    
    def _diagnose_business_performance(self, metrics, cm):
        """诊断业务性能"""
        print("\n🔍 业务性能诊断")
        print("=" * 50)
        
        tn, fp, fn, tp = cm.ravel()
        business_value = metrics['business_value']
        net_value = metrics['net_business_value']
        
        # 整体性能评估
        if business_value >= 0.8:
            print("✅ 优秀：业务价值很高，模型表现优异")
        elif business_value >= 0.6:
            print("✅ 良好：业务价值可接受，有进一步优化空间")
        elif business_value >= 0.4:
            print("⚠️  一般：业务价值偏低，需要重点优化")
        else:
            print("❌ 差：业务价值很低，模型需要重新设计")
        
        # 净值分析
        if net_value > 0:
            print(f"✅ 盈利模型：净创造价值 ¥{net_value:,}")
        else:
            print(f"❌ 亏损模型：净损失 ¥{abs(net_value):,}")
        
        # 风险分析
        false_negative_rate = fn / (fn + tp) if (fn + tp) > 0 else 0
        false_positive_rate = fp / (fp + tn) if (fp + tn) > 0 else 0
        
        if false_negative_rate <= 0.1:
            print("✅ 风险控制：假阴性率低，风险控制良好")
        elif false_negative_rate <= 0.2:
            print("⚠️  风险控制：假阴性率中等，需要注意风险")
        else:
            print("❌ 风险控制：假阴性率高，风险控制不足")
        
        # 机会成本分析
        if false_positive_rate <= 0.2:
            print("✅ 机会把握：假阳性率低，很少错失好客户")
        elif false_positive_rate <= 0.4:
            print("⚠️  机会把握：假阳性率中等，可能错失部分机会")
        else:
            print("❌ 机会把握：假阳性率高，错失过多商机")
    
    def analyze_model_insights(self):
        """分析模型洞察"""
        print("\n🔬 模型分析和洞察")
        print("=" * 60)
        
        # 显示最佳模型
        print("🏆 最优模型排行榜:")
        try:
            print(self.automl.leaderboard())
        except Exception as e:
            print(f"无法显示排行榜: {e}")
        
        print("\n🔧 最终集成模型构成:")
        try:
            print(self.automl.show_models())
        except Exception as e:
            print(f"无法显示模型详情: {e}")
        
        # 特征重要性分析
        try:
            print("\n📊 特征重要性分析:")
            # 这需要进一步实现...
            print("特征重要性分析需要单独实现")
        except Exception as e:
            print(f"特征重要性分析失败: {e}")
    
    def create_business_visualizations(self):
        """创建业务导向可视化图表"""
        print("\n正在生成业务分析可视化...")
        
        y_test = self.results['y_test']
        test_pred = self.results['test_predictions']
        test_pred_proba = self.results['test_pred_proba']
        cm = self.results['confusion_matrix']
        
        # 创建综合分析图表
        fig, axes = plt.subplots(2, 3, figsize=(18, 12))
        fig.suptitle('金融风控业务导向模型分析', fontsize=16, fontweight='bold')
        
        # 1. 混淆矩阵热图
        ax1 = axes[0, 0]
        sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', ax=ax1,
                   xticklabels=['好客户', '坏客户'],
                   yticklabels=['好客户', '坏客户'])
        ax1.set_title('混淆矩阵')
        ax1.set_xlabel('预测标签')
        ax1.set_ylabel('真实标签')
        
        # 2. 成本收益分析
        ax2 = axes[0, 1]
        tn, fp, fn, tp = cm.ravel()
        categories = ['误拒成本', '误批成本', '正确收益']
        values = [
            -fp * self.cost_matrix['fp_cost'],
            -fn * self.cost_matrix['fn_cost'], 
            tp * self.cost_matrix['tp_profit']
        ]
        colors = ['red', 'darkred', 'green']
        
        bars = ax2.bar(categories, values, color=colors, alpha=0.7)
        ax2.set_title('成本收益分析')
        ax2.set_ylabel('金额 (¥)')
        ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)
        
        # 添加数值标签
        for bar, value in zip(bars, values):
            height = bar.get_height()
            ax2.text(bar.get_x() + bar.get_width()/2., height,
                    f'¥{abs(value):,.0f}', ha='center', 
                    va='bottom' if height >= 0 else 'top')
        
        # 3. ROC曲线 (如果有概率预测)
        ax3 = axes[0, 2]
        if test_pred_proba is not None:
            fpr, tpr, _ = metrics.roc_curve(y_test, test_pred_proba[:, 1])
            auc = metrics.roc_auc_score(y_test, test_pred_proba[:, 1])
            ax3.plot(fpr, tpr, color='blue', label=f'ROC Curve (AUC = {auc:.3f})')
            ax3.plot([0, 1], [0, 1], color='red', linestyle='--', label='Random')
            ax3.set_xlabel('假阳性率')
            ax3.set_ylabel('真阳性率') 
            ax3.set_title('ROC曲线')
            ax3.legend()
            ax3.grid(True, alpha=0.3)
        else:
            ax3.text(0.5, 0.5, '无概率预测\\n无法绘制ROC曲线', 
                    ha='center', va='center', transform=ax3.transAxes)
            ax3.set_title('ROC曲线')
        
        # 4. 决策阈值分析
        ax4 = axes[1, 0]
        if test_pred_proba is not None:
            thresholds = np.linspace(0, 1, 100)
            business_values = []
            
            for threshold in thresholds:
                y_pred_thresh = (test_pred_proba[:, 1] >= threshold).astype(int)
                bv = self.business_metrics.business_value_score(
                    y_test, y_pred_thresh,
                    cost_fp=self.cost_matrix['fp_cost'],
                    cost_fn=self.cost_matrix['fn_cost'],
                    profit_tp=self.cost_matrix['tp_profit']
                )
                business_values.append(bv)
            
            ax4.plot(thresholds, business_values, color='green', linewidth=2)
            ax4.set_xlabel('决策阈值')
            ax4.set_ylabel('业务价值分数')
            ax4.set_title('决策阈值优化')
            ax4.grid(True, alpha=0.3)
            
            # 标记最优阈值
            optimal_idx = np.argmax(business_values)
            optimal_threshold = thresholds[optimal_idx]
            optimal_value = business_values[optimal_idx]
            ax4.axvline(x=optimal_threshold, color='red', linestyle='--')
            ax4.text(optimal_threshold, optimal_value, 
                    f'最优阈值: {optimal_threshold:.3f}', 
                    ha='center', va='bottom')
        else:
            ax4.text(0.5, 0.5, '无概率预测\\n无法分析阈值', 
                    ha='center', va='center', transform=ax4.transAxes)
            ax4.set_title('决策阈值分析')
        
        # 5. 指标对比雷达图
        ax5 = axes[1, 1]
        test_metrics = self.results['test_metrics']
        metric_names = ['Accuracy', 'Precision', 'Recall', 'F1', 'Business Value']
        metric_values = [
            test_metrics['accuracy'],
            test_metrics['precision'], 
            test_metrics['recall'],
            test_metrics['f1'],
            test_metrics['business_value']
        ]
        
        # 简化为条形图
        bars = ax5.barh(metric_names, metric_values, color='skyblue', alpha=0.7)
        ax5.set_xlabel('分数')
        ax5.set_title('性能指标对比')
        ax5.set_xlim(0, 1)
        
        # 添加数值标签
        for i, bar in enumerate(bars):
            width = bar.get_width()
            ax5.text(width + 0.01, bar.get_y() + bar.get_height()/2,
                    f'{metric_values[i]:.3f}', ha='left', va='center')
        
        # 6. 风险分布分析
        ax6 = axes[1, 2]
        if test_pred_proba is not None:
            # 按风险等级分组
            risk_scores = test_pred_proba[:, 1]
            risk_levels = ['低风险', '中低风险', '中高风险', '高风险']
            risk_boundaries = [0, 0.25, 0.5, 0.75, 1.0]
            
            risk_counts = []
            default_rates = []
            
            for i in range(len(risk_levels)):
                mask = (risk_scores >= risk_boundaries[i]) & (risk_scores < risk_boundaries[i+1])
                count = np.sum(mask)
                default_rate = np.mean(y_test[mask]) if count > 0 else 0
                risk_counts.append(count)
                default_rates.append(default_rate)
            
            # 双轴图
            ax6_twin = ax6.twinx()
            
            bars = ax6.bar(risk_levels, risk_counts, alpha=0.7, color='skyblue', label='客户数量')
            line = ax6_twin.plot(risk_levels, default_rates, color='red', marker='o', linewidth=2, label='违约率')
            
            ax6.set_ylabel('客户数量', color='blue')
            ax6_twin.set_ylabel('违约率', color='red')
            ax6.set_title('风险分布分析')
            ax6.tick_params(axis='x', rotation=45)
            
            # 图例
            lines1, labels1 = ax6.get_legend_handles_labels()
            lines2, labels2 = ax6_twin.get_legend_handles_labels()
            ax6.legend(lines1 + lines2, labels1 + labels2, loc='upper right')
        else:
            ax6.text(0.5, 0.5, '无概率预测\\n无法分析风险分布', 
                    ha='center', va='center', transform=ax6.transAxes)
            ax6.set_title('风险分布分析')
        
        plt.tight_layout()
        
        # 保存图表
        os.makedirs('../results', exist_ok=True)
        plt.savefig('../results/financial_risk_analysis.png', dpi=300, bbox_inches='tight')
        print("✅ 图表已保存至 ../results/financial_risk_analysis.png")
        
        return fig
    
    def save_model_and_results(self):
        """保存模型和结果"""
        print("\n正在保存模型和结果...")
        
        os.makedirs('../results', exist_ok=True)
        
        # 保存Auto-sklearn模型
        model_path = '../results/financial_risk_model.pkl'
        joblib.dump(self.automl, model_path)
        
        # 保存评估结果和配置
        results_path = '../results/financial_risk_results.pkl'
        save_results = {
            'results': self.results,
            'cost_matrix': self.cost_matrix,
            'custom_scorers': self.custom_scorers
        }
        joblib.dump(save_results, results_path)
        
        print(f"✅ 模型已保存至: {model_path}")
        print(f"✅ 结果已保存至: {results_path}")
    
    def generate_business_report(self):
        """生成业务导向应用报告"""
        print("\n📋 金融风控模型业务报告")
        print("=" * 60)
        
        test_metrics = self.results['test_metrics']
        cm = self.results['confusion_matrix']
        tn, fp, fn, tp = cm.ravel()
        
        print("🎯 模型性能摘要:")
        print(f"- 业务价值分数: {test_metrics['business_value']:.1%}")
        print(f"- 净业务价值: ¥{test_metrics['net_business_value']:,}")
        print(f"- 成本敏感准确率: {test_metrics['cost_sensitive_accuracy']:.1%}")
        
        print(f"\n📊 决策表现分析:")
        print(f"- 正确识别坏客户: {tp}/{tp+fn} ({tp/(tp+fn):.1%})")
        print(f"- 正确识别好客户: {tn}/{tn+fp} ({tn/(tn+fp):.1%})")
        print(f"- 误批坏客户损失: ¥{fn * self.cost_matrix['fn_cost']:,}")
        print(f"- 误拒好客户损失: ¥{fp * self.cost_matrix['fp_cost']:,}")
        
        print("\n💡 业务应用建议:")
        if test_metrics['net_business_value'] > 0:
            print("✅ 推荐部署：模型创造净正价值")
            if test_metrics['business_value'] >= 0.7:
                print("✅ 可用于自动化决策")
            else:
                print("⚠️  建议结合人工审核")
        else:
            print("❌ 不建议部署：模型造成净损失")
            print("⚠️  需要重新优化模型")
        
        print("\n🔄 持续改进建议:")
        if fn > tp * 0.2:  # 假阴性过多
            print("- 优化召回率，减少假阴性")
            print("- 考虑成本敏感采样")
        if fp > tn * 0.3:  # 假阳性过多  
            print("- 提高精度，减少假阳性")
            print("- 优化决策阈值")
        
        print("- 收集更多历史违约数据")
        print("- 引入外部数据源") 
        print("- 定期重训练和校准")
        print("- 建立模型监控体系")

def main():
    """主函数"""
    print("💰 金融风控自定义指标建模系统")
    print("=" * 60)
    
    # 创建分类器
    classifier = FinancialRiskClassifier(time_limit=600, per_run_limit=120)
    
    try:
        # 1. 数据加载和预处理
        X_train, X_test, y_train, y_test = classifier.load_and_prepare_data()
        
        # 2. 成本结构分析
        classifier.analyze_cost_structure(y_train, y_test)
        
        # 3. 创建自定义指标
        primary_metric = classifier.create_custom_metrics()
        
        # 4. 创建和训练模型
        classifier.create_automl_classifier(primary_metric)
        training_time = classifier.train_model(X_train, y_train)
        
        # 5. 模型评估
        train_metrics, test_metrics = classifier.evaluate_model(X_train, X_test, y_train, y_test)
        
        # 6. 模型分析
        classifier.analyze_model_insights()
        
        # 7. 业务可视化
        classifier.create_business_visualizations()
        
        # 8. 保存结果
        classifier.save_model_and_results()
        
        # 9. 生成业务报告
        classifier.generate_business_report()
        
        print(f"\n🎉 金融风控建模完成！总耗时: {training_time:.1f}秒")
        print("📂 结果文件保存在 ../results/ 目录中")
        
    except Exception as e:
        print(f"❌ 运行出错: {str(e)}")
        import traceback
        traceback.print_exc()
        raise

if __name__ == "__main__":
    main()